
#include "teximage.h"
#include "coid/comm/hash/hashkeyset.h"


bool TexImage::sw_surfaces = true;

////////////////////////////////////////////////////////////////////////////////
SDL_Surface* TexImage::create_surface( uint w, uint h, bool sw, SDL_Surface* surf, int x, int y )
{
    if(surf)
    {
        RASSERT( x>=0 && x+(int)w<=_surf->w );
        RASSERT( y>=0 && y+(int)h<=_surf->h );

        _surf = surf;
        _rect.x = (int16)x;
        _rect.y = (int16)y;
        _rect.w = (uint16)w;
        _rect.h = (uint16)h;

        return surf;
    }

    const uint32* rgbam = get_rgba_masks(_bpp);
    uint flags = sw ? SDL_SWSURFACE : SDL_HWSURFACE;

    //normally, 32bit surface has alpha
    if( _bpp == 32 )
        flags |= SDL_SRCALPHA;

    _surf = SDL_CreateRGBSurface( flags, w, h, _bpp,
        rgbam[0], rgbam[1], rgbam[2], rgbam[3] );

    return _surf;
}

////////////////////////////////////////////////////////////////////////////////
void TexImage::ColorizedSprite::create_from32( uint bpp, TexImage& img, TexImage* backg )
{
    DASSERT( bpp == 15 || bpp == 16 );
    DASSERT( img._bpp == 32 );
    DASSERT( !backg  ||  backg->_bpp == 32 );

    _bpp = bpp;

    uint bw,bh;
    const uint32* pback=0;
    if(backg)
    {
        pback = (const uint32*)backg->lock();
        bw = backg->width();
        bh = backg->height();
    }

    const uint32* pd = (const uint32*)img.lock();

    _data = _owndata.need_new(img.height());

    for( int i=0; i<img.height(); ++i )
    {
        t_line& row = _owndata[i];
        uint offs = 0;

        const uint32* pbackx;
        if(pback)
            pbackx = ptr_byteshift( pback, (i%bh) * backg->_surf->pitch );


        int st=-1;
        for( int j=0; j<img.width(); ++j )
        {
            const uchar* pb = (const uchar*)(pd+j);
            uint32 c = pd[j];

            int dg = pb[1] - pb[0];
            int dr = pb[2] - pb[0];

            if( pb[3] != 0xff )
            {
                c = scale_packed32( pb[3], c );

                //mix with background
                if(pback)
                    c += scale_packed32( 0xff-pb[3], pbackx[j%bw] );
            }

            if( pb[3] == 0 )
            {
                check_state( st, STATE_SKIP, row, offs );
            }
            else if( dg >= dr )
            {
                check_state( st, STATE_COLPRI, row, offs );
                add_coldata( st, c, row );
            }
            else if( dr )
            {
                check_state( st, STATE_COLSEC, row, offs );
                add_coldata( st, c, row );
            }
            else
            {
                check_state( st, STATE_COPY, row, offs );
                add_coldata( st, c, row );
            }
        }

        row[offs] = (uchar)st + xSTATE + 1;

        pd = ptr_byteshift( pd, img._surf->pitch );
    }

    img.unlock();
    if(backg)
        backg->unlock();

    _rect.x = 0;
    _rect.y = 0;
    _rect.w = img.width();
    _rect.h = img.height();
}

////////////////////////////////////////////////////////////////////////////////
struct Colorized : TexImage::ColorizedSprite::ColorizedKey
{
    TexImage img;
};

template<> struct hash<TexImage::ColorizedSprite::ColorizedKey>
{
    typedef TexImage::ColorizedSprite::ColorizedKey     type_key;

    uints operator()(const TexImage::ColorizedSprite::ColorizedKey& s) const
    {
        return (uints)s.that ^ *(const uint32*)&s.colpri;
    }
};

TexImage* TexImage::ColorizedSprite::get_cached( TexImage* backg )
{
    DASSERT( _ck.that == this );

    typedef TexImage::ColorizedSprite::ColorizedKey
        ColorizedKey;
    typedef hash_keyset< ColorizedKey,Colorized,_Select_GetRef<Colorized,ColorizedKey> >
        t_colhash;

    static t_colhash hash;

    const Colorized* cz = hash.find_value(_ck);
    if(cz)  return (TexImage*)&cz->img;

    Colorized* co = hash.insert_value_slot(_ck);
    *(ColorizedKey*)co = _ck;

    co->img.create( _rect.w, _rect.h, _bpp, TexImage::sw_surfaces );

    uint32 ct;
    if(backg)
        co->img.draw(*backg);
    else {
        ct = _ck.suggested_transparent(_bpp);
        co->img.fill( 0, 0, _rect.w, _rect.h, ct );
    }
    
    co->img.p_draw_colorize( *this, 0, 0 );

    if(!backg) {
        
        co->img.set_colorkey( true, ct, false );//true );
    }
    return &co->img;
}
